package ru.passivemoney.manage.job;

import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.passivemoney.common.Consts;
import ru.passivemoney.common.Utils;
import ru.passivemoney.common.UtilsOrders;
import ru.passivemoney.common.UtilsOrders.ActionUnderOrder;
import ru.passivemoney.manage.account.AccountHolder;
import ru.passivemoney.manage.messages.MessagesHolder;
import ru.passivemoney.manage.orders.OrdersHolder;
import ru.passivemoney.root.EngineHolder;

import com.dukascopy.api.IEngine;
import com.dukascopy.api.IEngine.OrderCommand;
import com.dukascopy.api.IMessage;
import com.dukascopy.api.IOrder;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.JFException;

/**
 * Задача на открытие ордера
 * @author Tarasov Artem
 *
 */
public class JobOO extends Job {
	
	private static final Logger logger = LoggerFactory.getLogger(JobOO.class);
	
	boolean bull;
	boolean useSL;
	Double askPrice;
	Double bidPrice;
	Instrument instrument;
	String orderLabel;
	
	public JobOO(boolean bull, boolean useSL, Double askPrice, Double bidPrice, Instrument instrument) {
		this.bull = bull;
		this.useSL = useSL;
		this.askPrice = askPrice;
		this.bidPrice = bidPrice;
		this.instrument = instrument;
		StringBuilder sb = new StringBuilder("Order_");
		sb.append(bull ? "bull_" : "bear_").append(instrument).append("_").append(Utils.SDF.format(new Date()));
		orderLabel = sb.toString();
		
		logger.info("JobOO id - {}. Creating new Job. Instrument - {}, {}, useSL - {}, askPrice - {}, bidPrice - {}",
				new Object[]{getId(), instrument, bull ? "bull" : "bear", useSL, askPrice, bidPrice});
	}

	@Override
	protected void execute() {
		if(Consts.MAX_COUNT_OPENED_ORDER <= OrdersHolder.getOpenedOrdersCount()){
			logger.info("JobOO id - {}. Max number of opened orders achieved.", getId());
			return;
		}
		
		String key = UtilsOrders.keyForSharedMap(order, ActionUnderOrder.SUBMIT);
		MessagesHolder.put(key, null);
		
   		try{
   			logger.info("JobOO id - {}. Trying to open order.", getId());
   			order = openOrder();
    			
   			while(MessagesHolder.get(key) == null){
   				timeCounter += minTimeToWait;
   				if(timeCounter > maxTimeToWait){
   					logger.error("JobOO id - {}. Open order error: Message doesn't come!", getId());
   					return;
   				}
   				Thread.sleep(minTimeToWait);
   			}
   			
   			//TODO: realize logic for incoming messages for order to open jobs
   			IMessage message = MessagesHolder.get(key);
   			
   			switch(message.getType()){
   				case ORDER_CHANGED_OK:
   					OrdersHolder.putToOpenedOrders(instrument, order);
   					break;
			default:
				break;
   					
   			}
    			
   			
    	}catch(Exception e){
    		logger.error("JobOO id - {}. Error when opening order.", getId());
    		logger.error("", e);
    	}finally{
    		MessagesHolder.remove(key);
    	}
	}
	
	protected IOrder openOrder() throws JFException{
    	IOrder out = null;
    	if(bull){
    		if(useSL){
    			out = openBullOrder(bidPrice - Consts.SL * instrument.getPipValue());
    		}else{
    			out = openBullOrder(0);
    		}
    	}else{
    		if(useSL){
    			out = openBearOrder(askPrice + Consts.SL * instrument.getPipValue());
    		}else{
    			out = openBearOrder(0);
    		}
    	}
    	return out;
    }
    
	protected IOrder openBullOrder(double stopLossPrice) throws JFException{
    	return openOrder(orderLabel, // label
				      	 IEngine.OrderCommand.BUY, // orderCommand
				      	AccountHolder.getCalculatedLotSize(instrument).doubleValue(), // amount
				      	 0, // price
				      	 Consts.SLIPPAGE, // slippage
				      	 stopLossPrice, // stopLossPrice
				      	 0); // takeProfitPrice
    }
    
	protected IOrder openBearOrder(double stopLossPrice) throws JFException{
    	return openOrder(orderLabel, // label
				   		 IEngine.OrderCommand.SELL, // orderCommand
				   		 AccountHolder.getCalculatedLotSize(instrument).doubleValue(), // amount
				   		 0, // price
				   		 Consts.SLIPPAGE, // slippage
				   		 stopLossPrice, // stopLossPrice
				   		 0); // takeProfitPrice
    }
	
	protected IOrder openOrder(String label, OrderCommand orderCommand, double amount, double price, double slippage, double stopLossPrice, double takeProfitPrice) throws JFException{
		if(amount == 0){
			logger.info("JobOO id - {}. Iinsufficient amount for opening order.", getId());
			return null;
		}
		
		StringBuilder sb = new StringBuilder("JobOO id - ").append(getId()).append(". Submiting order. ");
		sb.append("label - ").append(label).append(" ");
		sb.append("instrument - ").append(instrument).append(" ");
		sb.append("orderCommand - ").append(orderCommand).append(" ");
		sb.append("amount - ").append(amount).append(" ");
		sb.append("price - ").append(price).append(" ");
		sb.append("slippage - ").append(slippage).append(" ");
		sb.append("stopLossPrice - ").append(stopLossPrice).append(" ");
		sb.append("takeProfitPrice - ").append(takeProfitPrice).append(" ");
		logger.info(sb.toString());
		
		return EngineHolder.getEngine().submitOrder(label, instrument, orderCommand, amount, price, slippage, stopLossPrice, takeProfitPrice);
	}
    
}
